Home | History | Annotate | Download | only in src
      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 #define HB_SHAPER coretext
     30 #include "hb-shaper-impl-private.hh"
     31 
     32 #include "hb-coretext.h"
     33 
     34 
     35 #ifndef HB_DEBUG_CORETEXT
     36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
     37 #endif
     38 
     39 
     40 static void
     41 release_table_data (void *user_data)
     42 {
     43   CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
     44   CFRelease(cf_data);
     45 }
     46 
     47 static hb_blob_t *
     48 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
     49 {
     50   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
     51   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
     52   if (unlikely (!cf_data))
     53     return NULL;
     54 
     55   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
     56   const size_t length = CFDataGetLength (cf_data);
     57   if (!data || !length)
     58     return NULL;
     59 
     60   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
     61 			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
     62 			 release_table_data);
     63 }
     64 
     65 hb_face_t *
     66 hb_coretext_face_create (CGFontRef cg_font)
     67 {
     68   return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
     69 }
     70 
     71 
     72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
     73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
     74 
     75 
     76 /*
     77  * shaper face data
     78  */
     79 
     80 struct hb_coretext_shaper_face_data_t {
     81   CGFontRef cg_font;
     82 };
     83 
     84 static void
     85 release_data (void *info, const void *data, size_t size)
     86 {
     87   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
     88           hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
     89 
     90   hb_blob_destroy ((hb_blob_t *) info);
     91 }
     92 
     93 hb_coretext_shaper_face_data_t *
     94 _hb_coretext_shaper_face_data_create (hb_face_t *face)
     95 {
     96   hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
     97   if (unlikely (!data))
     98     return NULL;
     99 
    100   if (face->destroy == (hb_destroy_func_t) CGFontRelease)
    101   {
    102     data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
    103   }
    104   else
    105   {
    106     hb_blob_t *blob = hb_face_reference_blob (face);
    107     unsigned int blob_length;
    108     const char *blob_data = hb_blob_get_data (blob, &blob_length);
    109     if (unlikely (!blob_length))
    110       DEBUG_MSG (CORETEXT, face, "Face has empty blob");
    111 
    112     CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
    113     data->cg_font = CGFontCreateWithDataProvider (provider);
    114     CGDataProviderRelease (provider);
    115   }
    116 
    117   if (unlikely (!data->cg_font)) {
    118     DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
    119     free (data);
    120     return NULL;
    121   }
    122 
    123   return data;
    124 }
    125 
    126 void
    127 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
    128 {
    129   CFRelease (data->cg_font);
    130   free (data);
    131 }
    132 
    133 CGFontRef
    134 hb_coretext_face_get_cg_font (hb_face_t *face)
    135 {
    136   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
    137   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    138   return face_data->cg_font;
    139 }
    140 
    141 
    142 /*
    143  * shaper font data
    144  */
    145 
    146 struct hb_coretext_shaper_font_data_t {
    147   CTFontRef ct_font;
    148 };
    149 
    150 hb_coretext_shaper_font_data_t *
    151 _hb_coretext_shaper_font_data_create (hb_font_t *font)
    152 {
    153   if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
    154 
    155   hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
    156   if (unlikely (!data))
    157     return NULL;
    158 
    159   hb_face_t *face = font->face;
    160   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    161 
    162   data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
    163   if (unlikely (!data->ct_font)) {
    164     DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
    165     free (data);
    166     return NULL;
    167   }
    168 
    169   return data;
    170 }
    171 
    172 void
    173 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
    174 {
    175   CFRelease (data->ct_font);
    176   free (data);
    177 }
    178 
    179 
    180 /*
    181  * shaper shape_plan data
    182  */
    183 
    184 struct hb_coretext_shaper_shape_plan_data_t {};
    185 
    186 hb_coretext_shaper_shape_plan_data_t *
    187 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    188 					     const hb_feature_t *user_features HB_UNUSED,
    189 					     unsigned int        num_user_features HB_UNUSED)
    190 {
    191   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    192 }
    193 
    194 void
    195 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
    196 {
    197 }
    198 
    199 CTFontRef
    200 hb_coretext_font_get_ct_font (hb_font_t *font)
    201 {
    202   if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
    203   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    204   return font_data->ct_font;
    205 }
    206 
    207 
    208 /*
    209  * shaper
    210  */
    211 
    212 struct feature_record_t {
    213   unsigned int feature;
    214   unsigned int setting;
    215 };
    216 
    217 struct active_feature_t {
    218   feature_record_t rec;
    219   unsigned int order;
    220 
    221   static int cmp (const active_feature_t *a, const active_feature_t *b) {
    222     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
    223 	   a->order < b->order ? -1 : a->order > b->order ? 1 :
    224 	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
    225 	   0;
    226   }
    227   bool operator== (const active_feature_t *f) {
    228     return cmp (this, f) == 0;
    229   }
    230 };
    231 
    232 struct feature_event_t {
    233   unsigned int index;
    234   bool start;
    235   active_feature_t feature;
    236 
    237   static int cmp (const feature_event_t *a, const feature_event_t *b) {
    238     return a->index < b->index ? -1 : a->index > b->index ? 1 :
    239 	   a->start < b->start ? -1 : a->start > b->start ? 1 :
    240 	   active_feature_t::cmp (&a->feature, &b->feature);
    241   }
    242 };
    243 
    244 struct range_record_t {
    245   CTFontRef font;
    246   unsigned int index_first; /* == start */
    247   unsigned int index_last;  /* == end - 1 */
    248 };
    249 
    250 
    251 /* The following enum members are added in OS X 10.8. */
    252 #define kAltHalfWidthTextSelector		6
    253 #define kAltProportionalTextSelector		5
    254 #define kAlternateHorizKanaOffSelector		1
    255 #define kAlternateHorizKanaOnSelector		0
    256 #define kAlternateKanaType			34
    257 #define kAlternateVertKanaOffSelector		3
    258 #define kAlternateVertKanaOnSelector		2
    259 #define kCaseSensitiveLayoutOffSelector		1
    260 #define kCaseSensitiveLayoutOnSelector		0
    261 #define kCaseSensitiveLayoutType		33
    262 #define kCaseSensitiveSpacingOffSelector	3
    263 #define kCaseSensitiveSpacingOnSelector		2
    264 #define kContextualAlternatesOffSelector	1
    265 #define kContextualAlternatesOnSelector		0
    266 #define kContextualAlternatesType		36
    267 #define kContextualLigaturesOffSelector		19
    268 #define kContextualLigaturesOnSelector		18
    269 #define kContextualSwashAlternatesOffSelector	5
    270 #define kContextualSwashAlternatesOnSelector	4
    271 #define kDefaultLowerCaseSelector		0
    272 #define kDefaultUpperCaseSelector		0
    273 #define kHistoricalLigaturesOffSelector		21
    274 #define kHistoricalLigaturesOnSelector		20
    275 #define kHojoCharactersSelector			12
    276 #define kJIS2004CharactersSelector		11
    277 #define kLowerCasePetiteCapsSelector		2
    278 #define kLowerCaseSmallCapsSelector		1
    279 #define kLowerCaseType				37
    280 #define kMathematicalGreekOffSelector		11
    281 #define kMathematicalGreekOnSelector		10
    282 #define kNLCCharactersSelector			13
    283 #define kQuarterWidthTextSelector		4
    284 #define kScientificInferiorsSelector		4
    285 #define kStylisticAltEightOffSelector		17
    286 #define kStylisticAltEightOnSelector		16
    287 #define kStylisticAltEighteenOffSelector	37
    288 #define kStylisticAltEighteenOnSelector		36
    289 #define kStylisticAltElevenOffSelector		23
    290 #define kStylisticAltElevenOnSelector		22
    291 #define kStylisticAltFifteenOffSelector		31
    292 #define kStylisticAltFifteenOnSelector		30
    293 #define kStylisticAltFiveOffSelector		11
    294 #define kStylisticAltFiveOnSelector		10
    295 #define kStylisticAltFourOffSelector		9
    296 #define kStylisticAltFourOnSelector		8
    297 #define kStylisticAltFourteenOffSelector	29
    298 #define kStylisticAltFourteenOnSelector		28
    299 #define kStylisticAltNineOffSelector		19
    300 #define kStylisticAltNineOnSelector		18
    301 #define kStylisticAltNineteenOffSelector	39
    302 #define kStylisticAltNineteenOnSelector		38
    303 #define kStylisticAltOneOffSelector		3
    304 #define kStylisticAltOneOnSelector		2
    305 #define kStylisticAltSevenOffSelector		15
    306 #define kStylisticAltSevenOnSelector		14
    307 #define kStylisticAltSeventeenOffSelector	35
    308 #define kStylisticAltSeventeenOnSelector	34
    309 #define kStylisticAltSixOffSelector		13
    310 #define kStylisticAltSixOnSelector		12
    311 #define kStylisticAltSixteenOffSelector		33
    312 #define kStylisticAltSixteenOnSelector		32
    313 #define kStylisticAltTenOffSelector		21
    314 #define kStylisticAltTenOnSelector		20
    315 #define kStylisticAltThirteenOffSelector	27
    316 #define kStylisticAltThirteenOnSelector		26
    317 #define kStylisticAltThreeOffSelector		7
    318 #define kStylisticAltThreeOnSelector		6
    319 #define kStylisticAltTwelveOffSelector		25
    320 #define kStylisticAltTwelveOnSelector		24
    321 #define kStylisticAltTwentyOffSelector		41
    322 #define kStylisticAltTwentyOnSelector		40
    323 #define kStylisticAltTwoOffSelector		5
    324 #define kStylisticAltTwoOnSelector		4
    325 #define kStylisticAlternativesType		35
    326 #define kSwashAlternatesOffSelector		3
    327 #define kSwashAlternatesOnSelector		2
    328 #define kThirdWidthTextSelector			3
    329 #define kTraditionalNamesCharactersSelector	14
    330 #define kUpperCasePetiteCapsSelector		2
    331 #define kUpperCaseSmallCapsSelector		1
    332 #define kUpperCaseType				38
    333 
    334 /* Table data courtesy of Apple. */
    335 struct feature_mapping_t {
    336     FourCharCode otFeatureTag;
    337     uint16_t aatFeatureType;
    338     uint16_t selectorToEnable;
    339     uint16_t selectorToDisable;
    340 } feature_mappings[] = {
    341     { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
    342     { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
    343     { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
    344     { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
    345     { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
    346     { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
    347     { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
    348     { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
    349     { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
    350     { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
    351     { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
    352     { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
    353     { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
    354     { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
    355     { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
    356     { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
    357     { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
    358     { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
    359     { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
    360     { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
    361     { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
    362     { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
    363     { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
    364     { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
    365     { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
    366     { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
    367     { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
    368     { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
    369     { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
    370     { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
    371     { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
    372     { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
    373     { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
    374     { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
    375     { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
    376     { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
    377     { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
    378     { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
    379     { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
    380     { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
    381     { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
    382     { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
    383     { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
    384     { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
    385     { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
    386     { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
    387     { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
    388     { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
    389     { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
    390     { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
    391     { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
    392     { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
    393     { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
    394     { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
    395     { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
    396     { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
    397     { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
    398     { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
    399     { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
    400     { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
    401     { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
    402     { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
    403     { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
    404     { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
    405     { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
    406     { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
    407     { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
    408     { 'unic',   kLetterCaseType,            14,                                     15 },
    409     { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
    410     { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
    411     { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
    412     { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
    413     { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
    414     { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
    415     { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
    416 };
    417 
    418 static int
    419 _hb_feature_mapping_cmp (const void *key_, const void *entry_)
    420 {
    421   unsigned int key = * (unsigned int *) key_;
    422   const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
    423   return key < entry->otFeatureTag ? -1 :
    424 	 key > entry->otFeatureTag ? 1 :
    425 	 0;
    426 }
    427 
    428 hb_bool_t
    429 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
    430 		    hb_font_t          *font,
    431                     hb_buffer_t        *buffer,
    432                     const hb_feature_t *features,
    433                     unsigned int        num_features)
    434 {
    435   hb_face_t *face = font->face;
    436   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    437   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    438 
    439   /*
    440    * Set up features.
    441    * (copied + modified from code from hb-uniscribe.cc)
    442    */
    443   hb_auto_array_t<feature_record_t> feature_records;
    444   hb_auto_array_t<range_record_t> range_records;
    445   if (num_features)
    446   {
    447     /* Sort features by start/end events. */
    448     hb_auto_array_t<feature_event_t> feature_events;
    449     for (unsigned int i = 0; i < num_features; i++)
    450     {
    451       const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
    452 									       feature_mappings,
    453 									       ARRAY_LENGTH (feature_mappings),
    454 									       sizeof (feature_mappings[0]),
    455 									       _hb_feature_mapping_cmp);
    456       if (!mapping)
    457         continue;
    458 
    459       active_feature_t feature;
    460       feature.rec.feature = mapping->aatFeatureType;
    461       feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
    462       feature.order = i;
    463 
    464       feature_event_t *event;
    465 
    466       event = feature_events.push ();
    467       if (unlikely (!event))
    468 	goto fail_features;
    469       event->index = features[i].start;
    470       event->start = true;
    471       event->feature = feature;
    472 
    473       event = feature_events.push ();
    474       if (unlikely (!event))
    475 	goto fail_features;
    476       event->index = features[i].end;
    477       event->start = false;
    478       event->feature = feature;
    479     }
    480     feature_events.sort ();
    481     /* Add a strategic final event. */
    482     {
    483       active_feature_t feature;
    484       feature.rec.feature = HB_TAG_NONE;
    485       feature.rec.setting = 0;
    486       feature.order = num_features + 1;
    487 
    488       feature_event_t *event = feature_events.push ();
    489       if (unlikely (!event))
    490 	goto fail_features;
    491       event->index = 0; /* This value does magic. */
    492       event->start = false;
    493       event->feature = feature;
    494     }
    495 
    496     /* Scan events and save features for each range. */
    497     hb_auto_array_t<active_feature_t> active_features;
    498     unsigned int last_index = 0;
    499     for (unsigned int i = 0; i < feature_events.len; i++)
    500     {
    501       feature_event_t *event = &feature_events[i];
    502 
    503       if (event->index != last_index)
    504       {
    505         /* Save a snapshot of active features and the range. */
    506 	range_record_t *range = range_records.push ();
    507 	if (unlikely (!range))
    508 	  goto fail_features;
    509 
    510 	unsigned int offset = feature_records.len;
    511 
    512 	if (active_features.len)
    513 	{
    514 	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
    515 
    516 	  /* TODO sort and resolve conflicting features? */
    517 	  /* active_features.sort (); */
    518 	  for (unsigned int j = 0; j < active_features.len; j++)
    519 	  {
    520 	    CFStringRef keys[2] = {
    521 	      kCTFontFeatureTypeIdentifierKey,
    522 	      kCTFontFeatureSelectorIdentifierKey
    523 	    };
    524 	    CFNumberRef values[2] = {
    525 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
    526 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
    527 	    };
    528 	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
    529 						       (const void **) keys,
    530 						       (const void **) values,
    531 						       2,
    532 						       &kCFTypeDictionaryKeyCallBacks,
    533 						       &kCFTypeDictionaryValueCallBacks);
    534 	    CFRelease (values[0]);
    535 	    CFRelease (values[1]);
    536 
    537 	    CFArrayAppendValue (features_array, dict);
    538 	    CFRelease (dict);
    539 
    540 	  }
    541 
    542 	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
    543 							   (const void **) &kCTFontFeatureSettingsAttribute,
    544 							   (const void **) &features_array,
    545 							   1,
    546 							   &kCFTypeDictionaryKeyCallBacks,
    547 							   &kCFTypeDictionaryValueCallBacks);
    548 	  CFRelease (features_array);
    549 
    550 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
    551 	  CFRelease (attributes);
    552 
    553 	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
    554 
    555 	  CFRelease (font_desc);
    556 	}
    557 	else
    558 	{
    559 	  range->font = NULL;
    560 	}
    561 
    562 	range->index_first = last_index;
    563 	range->index_last  = event->index - 1;
    564 
    565 	last_index = event->index;
    566       }
    567 
    568       if (event->start) {
    569         active_feature_t *feature = active_features.push ();
    570 	if (unlikely (!feature))
    571 	  goto fail_features;
    572 	*feature = event->feature;
    573       } else {
    574         active_feature_t *feature = active_features.find (&event->feature);
    575 	if (feature)
    576 	  active_features.remove (feature - active_features.array);
    577       }
    578     }
    579 
    580     if (!range_records.len) /* No active feature found. */
    581       goto fail_features;
    582   }
    583   else
    584   {
    585   fail_features:
    586     num_features = 0;
    587   }
    588 
    589 #define FAIL(...) \
    590   HB_STMT_START { \
    591     DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
    592     return false; \
    593   } HB_STMT_END;
    594 
    595   unsigned int scratch_size;
    596   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
    597 
    598 #define ALLOCATE_ARRAY(Type, name, len) \
    599   Type *name = (Type *) scratch; \
    600   { \
    601     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    602     assert (_consumed <= scratch_size); \
    603     scratch += _consumed; \
    604     scratch_size -= _consumed; \
    605   }
    606 
    607 #define utf16_index() var1.u32
    608 
    609   ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
    610 
    611   unsigned int chars_len = 0;
    612   for (unsigned int i = 0; i < buffer->len; i++) {
    613     hb_codepoint_t c = buffer->info[i].codepoint;
    614     buffer->info[i].utf16_index() = chars_len;
    615     if (likely (c < 0x10000))
    616       pchars[chars_len++] = c;
    617     else if (unlikely (c >= 0x110000))
    618       pchars[chars_len++] = 0xFFFD;
    619     else {
    620       pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
    621       pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
    622     }
    623   }
    624 
    625 #undef utf16_index
    626 
    627   CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
    628                                                                pchars, chars_len,
    629                                                                kCFAllocatorNull);
    630 
    631   CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
    632   CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
    633   CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
    634 				  kCTFontAttributeName, font_data->ct_font);
    635 
    636   if (num_features)
    637   {
    638     ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
    639 
    640     /* Need log_clusters to assign features. */
    641     chars_len = 0;
    642     for (unsigned int i = 0; i < buffer->len; i++)
    643     {
    644       hb_codepoint_t c = buffer->info[i].codepoint;
    645       unsigned int cluster = buffer->info[i].cluster;
    646       log_clusters[chars_len++] = cluster;
    647       if (c >= 0x10000 && c < 0x110000)
    648 	log_clusters[chars_len++] = cluster; /* Surrogates. */
    649     }
    650 
    651     unsigned int start = 0;
    652     range_record_t *last_range = &range_records[0];
    653     for (unsigned int k = 0; k < chars_len; k++)
    654     {
    655       range_record_t *range = last_range;
    656       while (log_clusters[k] < range->index_first)
    657 	range--;
    658       while (log_clusters[k] > range->index_last)
    659 	range++;
    660       if (range != last_range)
    661       {
    662         if (last_range->font)
    663 	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
    664 					  kCTFontAttributeName, last_range->font);
    665 
    666 	start = k;
    667       }
    668 
    669       last_range = range;
    670     }
    671     if (start != chars_len && last_range->font)
    672       CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
    673 				      kCTFontAttributeName, last_range->font);
    674 
    675     for (unsigned int i = 0; i < range_records.len; i++)
    676       if (range_records[i].font)
    677 	CFRelease (range_records[i].font);
    678   }
    679 
    680   CTLineRef line = CTLineCreateWithAttributedString (attr_string);
    681   CFRelease (attr_string);
    682 
    683   CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
    684   unsigned int num_runs = CFArrayGetCount (glyph_runs);
    685 
    686   buffer->len = 0;
    687 
    688   const CFRange range_all = CFRangeMake (0, 0);
    689 
    690   for (unsigned int i = 0; i < num_runs; i++)
    691   {
    692     CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
    693 
    694     /* CoreText does automatic font fallback (AKA "cascading") for  characters
    695      * not supported by the requested font, and provides no way to turn it off,
    696      * so we detect if the returned run uses a font other than the requested
    697      * one and fill in the buffer with .notdef glyphs instead of random glyph
    698      * indices from a different font.
    699      */
    700     CFDictionaryRef attributes = CTRunGetAttributes (run);
    701     CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
    702     CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
    703     if (!CFEqual (run_cg_font, face_data->cg_font))
    704     {
    705         CFRelease (run_cg_font);
    706 
    707 	CFRange range = CTRunGetStringRange (run);
    708 	buffer->ensure (buffer->len + range.length);
    709 	if (buffer->in_error)
    710 	  FAIL ("Buffer resize failed");
    711 	hb_glyph_info_t *info = buffer->info + buffer->len;
    712 
    713 	CGGlyph notdef = 0;
    714 	double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
    715 
    716         for (CFIndex j = range.location; j < range.location + range.length; j++)
    717 	{
    718 	    UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
    719 	    if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
    720 	    {
    721 	      ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
    722 	      if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
    723 	        /* This is the second of a surrogate pair.  Don't need .notdef
    724 		 * for this one. */
    725 	        continue;
    726 	    }
    727 
    728             info->codepoint = notdef;
    729 	    /* TODO We have to fixup clusters later.  See vis_clusters in
    730 	     * hb-uniscribe.cc for example. */
    731             info->cluster = j;
    732 
    733             info->mask = advance;
    734             info->var1.u32 = 0;
    735             info->var2.u32 = 0;
    736 
    737 	    info++;
    738 	    buffer->len++;
    739         }
    740         continue;
    741     }
    742     CFRelease (run_cg_font);
    743 
    744     unsigned int num_glyphs = CTRunGetGlyphCount (run);
    745     if (num_glyphs == 0)
    746       continue;
    747 
    748     buffer->ensure (buffer->len + num_glyphs);
    749 
    750     scratch = buffer->get_scratch_buffer (&scratch_size);
    751 
    752     /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
    753      * succeed, and so copying data to our own buffer will be rare. */
    754 
    755     const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
    756     if (!glyphs) {
    757       ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
    758       CTRunGetGlyphs (run, range_all, glyph_buf);
    759       glyphs = glyph_buf;
    760     }
    761 
    762     const CGPoint* positions = CTRunGetPositionsPtr (run);
    763     if (!positions) {
    764       ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
    765       CTRunGetPositions (run, range_all, position_buf);
    766       positions = position_buf;
    767     }
    768 
    769     const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
    770     if (!string_indices) {
    771       ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
    772       CTRunGetStringIndices (run, range_all, index_buf);
    773       string_indices = index_buf;
    774     }
    775 
    776 #undef ALLOCATE_ARRAY
    777 
    778     double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
    779 
    780     for (unsigned int j = 0; j < num_glyphs; j++) {
    781       double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
    782 
    783       hb_glyph_info_t *info = &buffer->info[buffer->len];
    784 
    785       info->codepoint = glyphs[j];
    786       info->cluster = string_indices[j];
    787 
    788       /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
    789       info->mask = advance;
    790       info->var1.u32 = 0;
    791       info->var2.u32 = positions[j].y;
    792 
    793       buffer->len++;
    794     }
    795   }
    796 
    797   buffer->clear_positions ();
    798 
    799   unsigned int count = buffer->len;
    800   for (unsigned int i = 0; i < count; ++i) {
    801     hb_glyph_info_t *info = &buffer->info[i];
    802     hb_glyph_position_t *pos = &buffer->pos[i];
    803 
    804     /* TODO vertical */
    805     pos->x_advance = info->mask;
    806     pos->x_offset = info->var1.u32;
    807     pos->y_offset = info->var2.u32;
    808   }
    809 
    810   /* Fix up clusters so that we never return out-of-order indices;
    811    * if core text has reordered glyphs, we'll merge them to the
    812    * beginning of the reordered cluster.
    813    *
    814    * This does *not* mean we'll form the same clusters as Uniscribe
    815    * or the native OT backend, only that the cluster indices will be
    816    * monotonic in the output buffer. */
    817   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    818     unsigned int prev_cluster = 0;
    819     for (unsigned int i = 0; i < count; i++) {
    820       unsigned int curr_cluster = buffer->info[i].cluster;
    821       if (curr_cluster < prev_cluster) {
    822         for (unsigned int j = i; j > 0; j--) {
    823           if (buffer->info[j - 1].cluster > curr_cluster)
    824             buffer->info[j - 1].cluster = curr_cluster;
    825           else
    826             break;
    827         }
    828       }
    829       prev_cluster = curr_cluster;
    830     }
    831   } else {
    832     unsigned int prev_cluster = (unsigned int)-1;
    833     for (unsigned int i = 0; i < count; i++) {
    834       unsigned int curr_cluster = buffer->info[i].cluster;
    835       if (curr_cluster > prev_cluster) {
    836         for (unsigned int j = i; j > 0; j--) {
    837           if (buffer->info[j - 1].cluster < curr_cluster)
    838             buffer->info[j - 1].cluster = curr_cluster;
    839           else
    840             break;
    841         }
    842       }
    843       prev_cluster = curr_cluster;
    844     }
    845   }
    846 
    847   CFRelease (string_ref);
    848   CFRelease (line);
    849 
    850   return true;
    851 }
    852 
    853 
    854 /*
    855  * AAT shaper
    856  */
    857 
    858 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
    859 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
    860 
    861 
    862 /*
    863  * shaper face data
    864  */
    865 
    866 struct hb_coretext_aat_shaper_face_data_t {};
    867 
    868 hb_coretext_aat_shaper_face_data_t *
    869 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
    870 {
    871   hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
    872   /* Umm, we just reference the table to check whether it exists.
    873    * Maybe add better API for this? */
    874   if (!hb_blob_get_length (mort_blob))
    875   {
    876     hb_blob_destroy (mort_blob);
    877     mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
    878     if (!hb_blob_get_length (mort_blob))
    879     {
    880       hb_blob_destroy (mort_blob);
    881       return NULL;
    882     }
    883   }
    884   hb_blob_destroy (mort_blob);
    885 
    886   return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
    887 }
    888 
    889 void
    890 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
    891 {
    892 }
    893 
    894 
    895 /*
    896  * shaper font data
    897  */
    898 
    899 struct hb_coretext_aat_shaper_font_data_t {};
    900 
    901 hb_coretext_aat_shaper_font_data_t *
    902 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
    903 {
    904   return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
    905 }
    906 
    907 void
    908 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
    909 {
    910 }
    911 
    912 
    913 /*
    914  * shaper shape_plan data
    915  */
    916 
    917 struct hb_coretext_aat_shaper_shape_plan_data_t {};
    918 
    919 hb_coretext_aat_shaper_shape_plan_data_t *
    920 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    921 					     const hb_feature_t *user_features HB_UNUSED,
    922 					     unsigned int        num_user_features HB_UNUSED)
    923 {
    924   return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    925 }
    926 
    927 void
    928 _hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
    929 {
    930 }
    931 
    932 
    933 /*
    934  * shaper
    935  */
    936 
    937 hb_bool_t
    938 _hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
    939 			hb_font_t          *font,
    940 			hb_buffer_t        *buffer,
    941 			const hb_feature_t *features,
    942 			unsigned int        num_features)
    943 {
    944   return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
    945 }
    946