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
31#include "hb-private.hh"
32#include "hb-debug.hh"
33#include "hb-shaper-impl-private.hh"
34
35#include "hb-coretext.h"
36#include <math.h>
37
38/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
39#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
40
41static CGFloat
42coretext_font_size_from_ptem (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}
52static float
53coretext_font_size_to_ptem (CGFloat size)
54{
55  size *= 72.f / 96.f;
56  return size <= 0.f ? 0 : size;
57}
58
59static void
60release_table_data (void *user_data)
61{
62  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
63  CFRelease(cf_data);
64}
65
66static hb_blob_t *
67reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
68{
69  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
70  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
71  if (unlikely (!cf_data))
72    return nullptr;
73
74  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
75  const size_t length = CFDataGetLength (cf_data);
76  if (!data || !length)
77    return nullptr;
78
79  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
80			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
81			 release_table_data);
82}
83
84static void
85_hb_cg_font_release (void *data)
86{
87  CGFontRelease ((CGFontRef) data);
88}
89
90
91HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
92HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
93	fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) <= .5
94)
95
96static CTFontDescriptorRef
97get_last_resort_font_desc (void)
98{
99  // TODO Handle allocation failures?
100  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
101  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
102					   (const void **) &last_resort,
103					   1,
104					   &kCFTypeArrayCallBacks);
105  CFRelease (last_resort);
106  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
107						   (const void **) &kCTFontCascadeListAttribute,
108						   (const void **) &cascade_list,
109						   1,
110						   &kCFTypeDictionaryKeyCallBacks,
111						   &kCFTypeDictionaryValueCallBacks);
112  CFRelease (cascade_list);
113
114  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
115  CFRelease (attributes);
116  return font_desc;
117}
118
119static void
120release_data (void *info, const void *data, size_t size)
121{
122  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
123          hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
124
125  hb_blob_destroy ((hb_blob_t *) info);
126}
127
128static CGFontRef
129create_cg_font (hb_face_t *face)
130{
131  CGFontRef cg_font = nullptr;
132  if (face->destroy == _hb_cg_font_release)
133  {
134    cg_font = CGFontRetain ((CGFontRef) face->user_data);
135  }
136  else
137  {
138    hb_blob_t *blob = hb_face_reference_blob (face);
139    unsigned int blob_length;
140    const char *blob_data = hb_blob_get_data (blob, &blob_length);
141    if (unlikely (!blob_length))
142      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
143
144    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
145    if (likely (provider))
146    {
147      cg_font = CGFontCreateWithDataProvider (provider);
148      if (unlikely (!cg_font))
149	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
150      CGDataProviderRelease (provider);
151    }
152  }
153  return cg_font;
154}
155
156static CTFontRef
157create_ct_font (CGFontRef cg_font, CGFloat font_size)
158{
159  CTFontRef ct_font = nullptr;
160
161  /* CoreText does not enable trak table usage / tracking when creating a CTFont
162   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
163   * to be through the CTFontCreateUIFontForLanguage call. */
164  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
165  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
166      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
167  {
168    CTFontUIFontType font_type = kCTFontUIFontSystem;
169    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
170      font_type = kCTFontUIFontEmphasizedSystem;
171
172    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
173    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
174    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
175    {
176      CFRelease(ct_font);
177      ct_font = nullptr;
178    }
179    CFRelease (ct_result_name);
180  }
181  CFRelease (cg_postscript_name);
182
183  if (!ct_font)
184    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
185
186  if (unlikely (!ct_font)) {
187    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
188    return nullptr;
189  }
190
191  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
192   * bug indicate that the cascade list reconfiguration occasionally causes
193   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
194   * operating system versions. Except for the emoji font, where _not_
195   * reconfiguring the cascade list causes CoreText crashes. For details, see
196   * crbug.com/549610 */
197  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
198  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
199    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
200    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
201    CFRelease (fontName);
202    if (!isEmojiFont)
203      return ct_font;
204  }
205
206  CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
207
208  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
209   * font fallback which we don't need anyway. */
210  {
211    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
212    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
213    CFRelease (last_resort_font_desc);
214    if (new_ct_font)
215    {
216      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
217       * when reconfiguring the cascade list and may switch to a different font
218       * when there are fonts that go by the same name, since the descriptor is
219       * just name and size.
220       *
221       * Avoid reconfiguring the cascade lists if the new font is outside the
222       * system locations that we cannot access from the sandboxed renderer
223       * process in Blink. This can be detected by the new file URL location
224       * that the newly found font points to. */
225      CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
226      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
227      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
228      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
229        CFRelease (ct_font);
230        ct_font = new_ct_font;
231      } else {
232        CFRelease (new_ct_font);
233        DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
234      }
235      if (new_url)
236        CFRelease (new_url);
237    }
238    else
239      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
240  }
241
242  if (original_url)
243    CFRelease (original_url);
244  return ct_font;
245}
246
247hb_coretext_shaper_face_data_t *
248_hb_coretext_shaper_face_data_create (hb_face_t *face)
249{
250  CGFontRef cg_font = create_cg_font (face);
251
252  if (unlikely (!cg_font))
253  {
254    DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
255    return nullptr;
256  }
257
258  return (hb_coretext_shaper_face_data_t *) cg_font;
259}
260
261void
262_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
263{
264  CFRelease ((CGFontRef) data);
265}
266
267hb_face_t *
268hb_coretext_face_create (CGFontRef cg_font)
269{
270  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
271}
272
273/*
274 * Since: 0.9.10
275 */
276CGFontRef
277hb_coretext_face_get_cg_font (hb_face_t *face)
278{
279  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
280  return (CGFontRef) HB_SHAPER_DATA_GET (face);
281}
282
283
284hb_coretext_shaper_font_data_t *
285_hb_coretext_shaper_font_data_create (hb_font_t *font)
286{
287  hb_face_t *face = font->face;
288  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
289  CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
290
291  CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
292
293  if (unlikely (!ct_font))
294  {
295    DEBUG_MSG (CORETEXT, font, "CGFont creation failed..");
296    return nullptr;
297  }
298
299  return (hb_coretext_shaper_font_data_t *) ct_font;
300}
301
302void
303_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
304{
305  CFRelease ((CTFontRef) data);
306}
307
308/*
309 * Since: 1.7.2
310 */
311hb_font_t *
312hb_coretext_font_create (CTFontRef ct_font)
313{
314  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, 0);
315  hb_face_t *face = hb_coretext_face_create (cg_font);
316  CFRelease (cg_font);
317  hb_font_t *font = hb_font_create (face);
318  hb_face_destroy (face);
319
320  if (unlikely (hb_object_is_inert (font)))
321    return font;
322
323  hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
324
325  /* Let there be dragons here... */
326  HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
327
328  return font;
329}
330
331CTFontRef
332hb_coretext_font_get_ct_font (hb_font_t *font)
333{
334  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
335  return (CTFontRef) HB_SHAPER_DATA_GET (font);
336}
337
338
339
340/*
341 * shaper shape_plan data
342 */
343
344struct hb_coretext_shaper_shape_plan_data_t {};
345
346hb_coretext_shaper_shape_plan_data_t *
347_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
348					     const hb_feature_t *user_features HB_UNUSED,
349					     unsigned int        num_user_features HB_UNUSED,
350					     const int          *coords HB_UNUSED,
351					     unsigned int        num_coords HB_UNUSED)
352{
353  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
354}
355
356void
357_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
358{
359}
360
361
362/*
363 * shaper
364 */
365
366struct feature_record_t {
367  unsigned int feature;
368  unsigned int setting;
369};
370
371struct active_feature_t {
372  feature_record_t rec;
373  unsigned int order;
374
375  static int cmp (const void *pa, const void *pb) {
376    const active_feature_t *a = (const active_feature_t *) pa;
377    const active_feature_t *b = (const active_feature_t *) pb;
378    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
379	   a->order < b->order ? -1 : a->order > b->order ? 1 :
380	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
381	   0;
382  }
383  bool operator== (const active_feature_t *f) {
384    return cmp (this, f) == 0;
385  }
386};
387
388struct feature_event_t {
389  unsigned int index;
390  bool start;
391  active_feature_t feature;
392
393  static int cmp (const void *pa, const void *pb) {
394    const feature_event_t *a = (const feature_event_t *) pa;
395    const feature_event_t *b = (const feature_event_t *) pb;
396    return a->index < b->index ? -1 : a->index > b->index ? 1 :
397	   a->start < b->start ? -1 : a->start > b->start ? 1 :
398	   active_feature_t::cmp (&a->feature, &b->feature);
399  }
400};
401
402struct range_record_t {
403  CTFontRef font;
404  unsigned int index_first; /* == start */
405  unsigned int index_last;  /* == end - 1 */
406};
407
408
409/* The following enum members are added in OS X 10.8. */
410#define kAltHalfWidthTextSelector		6
411#define kAltProportionalTextSelector		5
412#define kAlternateHorizKanaOffSelector		1
413#define kAlternateHorizKanaOnSelector		0
414#define kAlternateKanaType			34
415#define kAlternateVertKanaOffSelector		3
416#define kAlternateVertKanaOnSelector		2
417#define kCaseSensitiveLayoutOffSelector		1
418#define kCaseSensitiveLayoutOnSelector		0
419#define kCaseSensitiveLayoutType		33
420#define kCaseSensitiveSpacingOffSelector	3
421#define kCaseSensitiveSpacingOnSelector		2
422#define kContextualAlternatesOffSelector	1
423#define kContextualAlternatesOnSelector		0
424#define kContextualAlternatesType		36
425#define kContextualLigaturesOffSelector		19
426#define kContextualLigaturesOnSelector		18
427#define kContextualSwashAlternatesOffSelector	5
428#define kContextualSwashAlternatesOnSelector	4
429#define kDefaultLowerCaseSelector		0
430#define kDefaultUpperCaseSelector		0
431#define kHistoricalLigaturesOffSelector		21
432#define kHistoricalLigaturesOnSelector		20
433#define kHojoCharactersSelector			12
434#define kJIS2004CharactersSelector		11
435#define kLowerCasePetiteCapsSelector		2
436#define kLowerCaseSmallCapsSelector		1
437#define kLowerCaseType				37
438#define kMathematicalGreekOffSelector		11
439#define kMathematicalGreekOnSelector		10
440#define kNLCCharactersSelector			13
441#define kQuarterWidthTextSelector		4
442#define kScientificInferiorsSelector		4
443#define kStylisticAltEightOffSelector		17
444#define kStylisticAltEightOnSelector		16
445#define kStylisticAltEighteenOffSelector	37
446#define kStylisticAltEighteenOnSelector		36
447#define kStylisticAltElevenOffSelector		23
448#define kStylisticAltElevenOnSelector		22
449#define kStylisticAltFifteenOffSelector		31
450#define kStylisticAltFifteenOnSelector		30
451#define kStylisticAltFiveOffSelector		11
452#define kStylisticAltFiveOnSelector		10
453#define kStylisticAltFourOffSelector		9
454#define kStylisticAltFourOnSelector		8
455#define kStylisticAltFourteenOffSelector	29
456#define kStylisticAltFourteenOnSelector		28
457#define kStylisticAltNineOffSelector		19
458#define kStylisticAltNineOnSelector		18
459#define kStylisticAltNineteenOffSelector	39
460#define kStylisticAltNineteenOnSelector		38
461#define kStylisticAltOneOffSelector		3
462#define kStylisticAltOneOnSelector		2
463#define kStylisticAltSevenOffSelector		15
464#define kStylisticAltSevenOnSelector		14
465#define kStylisticAltSeventeenOffSelector	35
466#define kStylisticAltSeventeenOnSelector	34
467#define kStylisticAltSixOffSelector		13
468#define kStylisticAltSixOnSelector		12
469#define kStylisticAltSixteenOffSelector		33
470#define kStylisticAltSixteenOnSelector		32
471#define kStylisticAltTenOffSelector		21
472#define kStylisticAltTenOnSelector		20
473#define kStylisticAltThirteenOffSelector	27
474#define kStylisticAltThirteenOnSelector		26
475#define kStylisticAltThreeOffSelector		7
476#define kStylisticAltThreeOnSelector		6
477#define kStylisticAltTwelveOffSelector		25
478#define kStylisticAltTwelveOnSelector		24
479#define kStylisticAltTwentyOffSelector		41
480#define kStylisticAltTwentyOnSelector		40
481#define kStylisticAltTwoOffSelector		5
482#define kStylisticAltTwoOnSelector		4
483#define kStylisticAlternativesType		35
484#define kSwashAlternatesOffSelector		3
485#define kSwashAlternatesOnSelector		2
486#define kThirdWidthTextSelector			3
487#define kTraditionalNamesCharactersSelector	14
488#define kUpperCasePetiteCapsSelector		2
489#define kUpperCaseSmallCapsSelector		1
490#define kUpperCaseType				38
491
492/* Table data courtesy of Apple. */
493static const struct feature_mapping_t {
494    FourCharCode otFeatureTag;
495    uint16_t aatFeatureType;
496    uint16_t selectorToEnable;
497    uint16_t selectorToDisable;
498} feature_mappings[] = {
499    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
500    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
501    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
502    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
503    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
504    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
505    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
506    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
507    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
508    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
509    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
510    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
511    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
512    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
513    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
514    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
515    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
516    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
517    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
518    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
519    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
520    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
521    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
522    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
523    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
524    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
525    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
526    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
527    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
528    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
529    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
530    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
531    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
532    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
533    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
534    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
535    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
536    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
537    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
538    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
539    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
540    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
541    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
542    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
543    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
544    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
545    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
546    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
547    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
548    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
549    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
550    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
551    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
552    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
553    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
554    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
555    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
556    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
557    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
558    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
559    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
560    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
561    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
562    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
563    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
564    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
565    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
566    { 'unic',   kLetterCaseType,            14,                                     15 },
567    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
568    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
569    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
570    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
571    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
572    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
573    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
574};
575
576static int
577_hb_feature_mapping_cmp (const void *key_, const void *entry_)
578{
579  unsigned int key = * (unsigned int *) key_;
580  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
581  return key < entry->otFeatureTag ? -1 :
582	 key > entry->otFeatureTag ? 1 :
583	 0;
584}
585
586hb_bool_t
587_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
588		    hb_font_t          *font,
589                    hb_buffer_t        *buffer,
590                    const hb_feature_t *features,
591                    unsigned int        num_features)
592{
593  hb_face_t *face = font->face;
594  CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
595  CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
596
597  CGFloat ct_font_size = CTFontGetSize (ct_font);
598  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
599  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
600
601  /* Attach marks to their bases, to match the 'ot' shaper.
602   * Adapted from hb-ot-shape:hb_form_clusters().
603   * Note that this only makes us be closer to the 'ot' shaper,
604   * but by no means the same.  For example, if there's
605   * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
606   * continue pointing to B2 even though B2 was merged into B1's
607   * cluster... */
608  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
609  {
610    hb_unicode_funcs_t *unicode = buffer->unicode;
611    unsigned int count = buffer->len;
612    hb_glyph_info_t *info = buffer->info;
613    for (unsigned int i = 1; i < count; i++)
614      if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
615	buffer->merge_clusters (i - 1, i + 1);
616  }
617
618  hb_auto_array_t<feature_record_t> feature_records;
619  hb_auto_array_t<range_record_t> range_records;
620
621  /*
622   * Set up features.
623   * (copied + modified from code from hb-uniscribe.cc)
624   */
625  if (num_features)
626  {
627    /* Sort features by start/end events. */
628    hb_auto_array_t<feature_event_t> feature_events;
629    for (unsigned int i = 0; i < num_features; i++)
630    {
631      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
632									       feature_mappings,
633									       ARRAY_LENGTH (feature_mappings),
634									       sizeof (feature_mappings[0]),
635									       _hb_feature_mapping_cmp);
636      if (!mapping)
637        continue;
638
639      active_feature_t feature;
640      feature.rec.feature = mapping->aatFeatureType;
641      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
642      feature.order = i;
643
644      feature_event_t *event;
645
646      event = feature_events.push ();
647      if (unlikely (!event))
648	goto fail_features;
649      event->index = features[i].start;
650      event->start = true;
651      event->feature = feature;
652
653      event = feature_events.push ();
654      if (unlikely (!event))
655	goto fail_features;
656      event->index = features[i].end;
657      event->start = false;
658      event->feature = feature;
659    }
660    feature_events.qsort ();
661    /* Add a strategic final event. */
662    {
663      active_feature_t feature;
664      feature.rec.feature = HB_TAG_NONE;
665      feature.rec.setting = 0;
666      feature.order = num_features + 1;
667
668      feature_event_t *event = feature_events.push ();
669      if (unlikely (!event))
670	goto fail_features;
671      event->index = 0; /* This value does magic. */
672      event->start = false;
673      event->feature = feature;
674    }
675
676    /* Scan events and save features for each range. */
677    hb_auto_array_t<active_feature_t> active_features;
678    unsigned int last_index = 0;
679    for (unsigned int i = 0; i < feature_events.len; i++)
680    {
681      feature_event_t *event = &feature_events[i];
682
683      if (event->index != last_index)
684      {
685        /* Save a snapshot of active features and the range. */
686	range_record_t *range = range_records.push ();
687	if (unlikely (!range))
688	  goto fail_features;
689
690	if (active_features.len)
691	{
692	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
693
694	  /* TODO sort and resolve conflicting features? */
695	  /* active_features.qsort (); */
696	  for (unsigned int j = 0; j < active_features.len; j++)
697	  {
698	    CFStringRef keys[] = {
699	      kCTFontFeatureTypeIdentifierKey,
700	      kCTFontFeatureSelectorIdentifierKey
701	    };
702	    CFNumberRef values[] = {
703	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
704	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
705	    };
706	    static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
707	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
708						       (const void **) keys,
709						       (const void **) values,
710						       ARRAY_LENGTH (keys),
711						       &kCFTypeDictionaryKeyCallBacks,
712						       &kCFTypeDictionaryValueCallBacks);
713	    for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
714	      CFRelease (values[i]);
715
716	    CFArrayAppendValue (features_array, dict);
717	    CFRelease (dict);
718
719	  }
720
721	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
722							   (const void **) &kCTFontFeatureSettingsAttribute,
723							   (const void **) &features_array,
724							   1,
725							   &kCFTypeDictionaryKeyCallBacks,
726							   &kCFTypeDictionaryValueCallBacks);
727	  CFRelease (features_array);
728
729	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
730	  CFRelease (attributes);
731
732	  range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, font_desc);
733	  CFRelease (font_desc);
734	}
735	else
736	{
737	  range->font = nullptr;
738	}
739
740	range->index_first = last_index;
741	range->index_last  = event->index - 1;
742
743	last_index = event->index;
744      }
745
746      if (event->start) {
747        active_feature_t *feature = active_features.push ();
748	if (unlikely (!feature))
749	  goto fail_features;
750	*feature = event->feature;
751      } else {
752        active_feature_t *feature = active_features.find (&event->feature);
753	if (feature)
754	  active_features.remove (feature - active_features.array);
755      }
756    }
757  }
758  else
759  {
760  fail_features:
761    num_features = 0;
762  }
763
764  unsigned int scratch_size;
765  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
766
767#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
768  Type *name = (Type *) scratch; \
769  { \
770    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
771    if (unlikely (_consumed > scratch_size)) \
772    { \
773      on_no_room; \
774      assert (0); \
775    } \
776    scratch += _consumed; \
777    scratch_size -= _consumed; \
778  }
779
780  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
781  unsigned int chars_len = 0;
782  for (unsigned int i = 0; i < buffer->len; i++) {
783    hb_codepoint_t c = buffer->info[i].codepoint;
784    if (likely (c <= 0xFFFFu))
785      pchars[chars_len++] = c;
786    else if (unlikely (c > 0x10FFFFu))
787      pchars[chars_len++] = 0xFFFDu;
788    else {
789      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
790      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
791    }
792  }
793
794  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
795  chars_len = 0;
796  for (unsigned int i = 0; i < buffer->len; i++)
797  {
798    hb_codepoint_t c = buffer->info[i].codepoint;
799    unsigned int cluster = buffer->info[i].cluster;
800    log_clusters[chars_len++] = cluster;
801    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
802      log_clusters[chars_len++] = cluster; /* Surrogates. */
803  }
804
805#define FAIL(...) \
806  HB_STMT_START { \
807    DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
808    ret = false; \
809    goto fail; \
810  } HB_STMT_END;
811
812  bool ret = true;
813  CFStringRef string_ref = nullptr;
814  CTLineRef line = nullptr;
815
816  if (0)
817  {
818resize_and_retry:
819    DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
820    /* string_ref uses the scratch-buffer for backing store, and line references
821     * string_ref (via attr_string).  We must release those before resizing buffer. */
822    assert (string_ref);
823    assert (line);
824    CFRelease (string_ref);
825    CFRelease (line);
826    string_ref = nullptr;
827    line = nullptr;
828
829    /* Get previous start-of-scratch-area, that we use later for readjusting
830     * our existing scratch arrays. */
831    unsigned int old_scratch_used;
832    hb_buffer_t::scratch_buffer_t *old_scratch;
833    old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
834    old_scratch_used = scratch - old_scratch;
835
836    if (unlikely (!buffer->ensure (buffer->allocated * 2)))
837      FAIL ("Buffer resize failed");
838
839    /* Adjust scratch, pchars, and log_cluster arrays.  This is ugly, but really the
840     * cleanest way to do without completely restructuring the rest of this shaper. */
841    scratch = buffer->get_scratch_buffer (&scratch_size);
842    pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
843    log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
844    scratch += old_scratch_used;
845    scratch_size -= old_scratch_used;
846  }
847  {
848    string_ref = CFStringCreateWithCharactersNoCopy (nullptr,
849						     pchars, chars_len,
850						     kCFAllocatorNull);
851    if (unlikely (!string_ref))
852      FAIL ("CFStringCreateWithCharactersNoCopy failed");
853
854    /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
855    {
856      CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
857										  chars_len);
858      if (unlikely (!attr_string))
859	FAIL ("CFAttributedStringCreateMutable failed");
860      CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
861      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
862      {
863	CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
864					kCTVerticalFormsAttributeName, kCFBooleanTrue);
865      }
866
867      if (buffer->props.language)
868      {
869/* What's the iOS equivalent of this check?
870 * The symbols was introduced in iOS 7.0.
871 * At any rate, our fallback is safe and works fine. */
872#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
873#  define kCTLanguageAttributeName CFSTR ("NSLanguage")
874#endif
875        CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
876							    hb_language_to_string (buffer->props.language),
877							    kCFStringEncodingUTF8,
878							    kCFAllocatorNull);
879	if (unlikely (!lang))
880	  FAIL ("CFStringCreateWithCStringNoCopy failed");
881	CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
882					kCTLanguageAttributeName, lang);
883	CFRelease (lang);
884      }
885      CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
886				      kCTFontAttributeName, ct_font);
887
888      if (num_features && range_records.len)
889      {
890	unsigned int start = 0;
891	range_record_t *last_range = &range_records[0];
892	for (unsigned int k = 0; k < chars_len; k++)
893	{
894	  range_record_t *range = last_range;
895	  while (log_clusters[k] < range->index_first)
896	    range--;
897	  while (log_clusters[k] > range->index_last)
898	    range++;
899	  if (range != last_range)
900	  {
901	    if (last_range->font)
902	      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
903					      kCTFontAttributeName, last_range->font);
904
905	    start = k;
906	  }
907
908	  last_range = range;
909	}
910	if (start != chars_len && last_range->font)
911	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
912					  kCTFontAttributeName, last_range->font);
913      }
914      /* Enable/disable kern if requested.
915       *
916       * Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
917       */
918      if (num_features)
919      {
920	unsigned int zeroint = 0;
921	CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
922	for (unsigned int i = 0; i < num_features; i++)
923	{
924	  const hb_feature_t &feature = features[i];
925	  if (feature.tag == HB_TAG('k','e','r','n') &&
926	      feature.start < chars_len && feature.start < feature.end)
927	  {
928	    CFRange feature_range = CFRangeMake (feature.start,
929	                                         MIN (feature.end, chars_len) - feature.start);
930	    if (feature.value)
931	      CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
932	    else
933	      CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
934	  }
935	}
936	CFRelease (zero);
937      }
938
939      int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
940      CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
941      CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
942						    (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
943						    (const void **) &level_number,
944						    1,
945						    &kCFTypeDictionaryKeyCallBacks,
946						    &kCFTypeDictionaryValueCallBacks);
947      CFRelease (level_number);
948      if (unlikely (!options))
949        FAIL ("CFDictionaryCreate failed");
950
951      CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
952      CFRelease (options);
953      CFRelease (attr_string);
954      if (unlikely (!typesetter))
955	FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
956
957      line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
958      CFRelease (typesetter);
959      if (unlikely (!line))
960	FAIL ("CTTypesetterCreateLine failed");
961    }
962
963    CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
964    unsigned int num_runs = CFArrayGetCount (glyph_runs);
965    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
966
967    buffer->len = 0;
968    uint32_t status_and = ~0, status_or = 0;
969    double advances_so_far = 0;
970    /* For right-to-left runs, CoreText returns the glyphs positioned such that
971     * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
972     * to fix for that.  Test with any RTL string with trailing spaces.
973     * https://code.google.com/p/chromium/issues/detail?id=469028
974     */
975    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
976    {
977      advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
978      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
979	  advances_so_far = -advances_so_far;
980    }
981
982    const CFRange range_all = CFRangeMake (0, 0);
983
984    for (unsigned int i = 0; i < num_runs; i++)
985    {
986      CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
987      CTRunStatus run_status = CTRunGetStatus (run);
988      status_or  |= run_status;
989      status_and &= run_status;
990      DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
991      double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
992      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
993	  run_advance = -run_advance;
994      DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
995
996      /* CoreText does automatic font fallback (AKA "cascading") for  characters
997       * not supported by the requested font, and provides no way to turn it off,
998       * so we must detect if the returned run uses a font other than the requested
999       * one and fill in the buffer with .notdef glyphs instead of random glyph
1000       * indices from a different font.
1001       */
1002      CFDictionaryRef attributes = CTRunGetAttributes (run);
1003      CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
1004      if (!CFEqual (run_ct_font, ct_font))
1005      {
1006	/* The run doesn't use our main font instance.  We have to figure out
1007	 * whether font fallback happened, or this is just CoreText giving us
1008	 * another CTFont using the same underlying CGFont.  CoreText seems
1009	 * to do that in a variety of situations, one of which being vertical
1010	 * text, but also perhaps for caching reasons.
1011	 *
1012	 * First, see if it uses any of our subfonts created to set font features...
1013	 *
1014	 * Next, compare the CGFont to the one we used to create our fonts.
1015	 * Even this doesn't work all the time.
1016	 *
1017	 * Finally, we compare PS names, which I don't think are unique...
1018	 *
1019	 * Looks like if we really want to be sure here we have to modify the
1020	 * font to change the name table, similar to what we do in the uniscribe
1021	 * backend.
1022	 *
1023	 * However, even that wouldn't work if we were passed in the CGFont to
1024	 * construct a hb_face to begin with.
1025	 *
1026	 * See: http://github.com/harfbuzz/harfbuzz/pull/36
1027	 *
1028	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
1029	 */
1030	bool matched = false;
1031	for (unsigned int i = 0; i < range_records.len; i++)
1032	  if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
1033	  {
1034	    matched = true;
1035	    break;
1036	  }
1037	if (!matched)
1038	{
1039	  CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
1040	  if (run_cg_font)
1041	  {
1042	    matched = CFEqual (run_cg_font, cg_font);
1043	    CFRelease (run_cg_font);
1044	  }
1045	}
1046	if (!matched)
1047	{
1048	  CFStringRef font_ps_name = CTFontCopyName (ct_font, kCTFontPostScriptNameKey);
1049	  CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
1050	  CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
1051	  CFRelease (run_ps_name);
1052	  CFRelease (font_ps_name);
1053	  if (result == kCFCompareEqualTo)
1054	    matched = true;
1055	}
1056	if (!matched)
1057	{
1058	  CFRange range = CTRunGetStringRange (run);
1059          DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
1060		     range.location, range.location + range.length);
1061	  if (!buffer->ensure_inplace (buffer->len + range.length))
1062	    goto resize_and_retry;
1063	  hb_glyph_info_t *info = buffer->info + buffer->len;
1064
1065	  hb_codepoint_t notdef = 0;
1066	  hb_direction_t dir = buffer->props.direction;
1067	  hb_position_t x_advance, y_advance, x_offset, y_offset;
1068	  hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
1069	  hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
1070	  hb_position_t advance = x_advance + y_advance;
1071	  x_offset = -x_offset;
1072	  y_offset = -y_offset;
1073
1074	  unsigned int old_len = buffer->len;
1075	  for (CFIndex j = range.location; j < range.location + range.length; j++)
1076	  {
1077	      UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
1078	      if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
1079	      {
1080		ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
1081		if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
1082		  /* This is the second of a surrogate pair.  Don't need .notdef
1083		   * for this one. */
1084		  continue;
1085	      }
1086	      if (buffer->unicode->is_default_ignorable (ch))
1087	        continue;
1088
1089	      info->codepoint = notdef;
1090	      info->cluster = log_clusters[j];
1091
1092	      info->mask = advance;
1093	      info->var1.i32 = x_offset;
1094	      info->var2.i32 = y_offset;
1095
1096	      info++;
1097	      buffer->len++;
1098	  }
1099	  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
1100	    buffer->reverse_range (old_len, buffer->len);
1101	  advances_so_far += run_advance;
1102	  continue;
1103	}
1104      }
1105
1106      unsigned int num_glyphs = CTRunGetGlyphCount (run);
1107      if (num_glyphs == 0)
1108	continue;
1109
1110      if (!buffer->ensure_inplace (buffer->len + num_glyphs))
1111	goto resize_and_retry;
1112
1113      hb_glyph_info_t *run_info = buffer->info + buffer->len;
1114
1115      /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
1116       * succeed, and so copying data to our own buffer will be rare.  Reports
1117       * have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
1118       * frequently.  At any rate, we can test that codepath by setting USE_PTR
1119       * to false. */
1120
1121#define USE_PTR true
1122
1123#define SCRATCH_SAVE() \
1124  unsigned int scratch_size_saved = scratch_size; \
1125  hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
1126
1127#define SCRATCH_RESTORE() \
1128  scratch_size = scratch_size_saved; \
1129  scratch = scratch_saved;
1130
1131      { /* Setup glyphs */
1132        SCRATCH_SAVE();
1133	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
1134	if (!glyphs) {
1135	  ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
1136	  CTRunGetGlyphs (run, range_all, glyph_buf);
1137	  glyphs = glyph_buf;
1138	}
1139	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
1140	if (!string_indices) {
1141	  ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
1142	  CTRunGetStringIndices (run, range_all, index_buf);
1143	  string_indices = index_buf;
1144	}
1145	hb_glyph_info_t *info = run_info;
1146	for (unsigned int j = 0; j < num_glyphs; j++)
1147	{
1148	  info->codepoint = glyphs[j];
1149	  info->cluster = log_clusters[string_indices[j]];
1150	  info++;
1151	}
1152	SCRATCH_RESTORE();
1153      }
1154      {
1155        /* Setup positions.
1156	 * Note that CoreText does not return advances for glyphs.  As such,
1157	 * for all but last glyph, we use the delta position to next glyph as
1158	 * advance (in the advance direction only), and for last glyph we set
1159	 * whatever is needed to make the whole run's advance add up. */
1160        SCRATCH_SAVE();
1161	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
1162	if (!positions) {
1163	  ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
1164	  CTRunGetPositions (run, range_all, position_buf);
1165	  positions = position_buf;
1166	}
1167	hb_glyph_info_t *info = run_info;
1168	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
1169	{
1170	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
1171	  for (unsigned int j = 0; j < num_glyphs; j++)
1172	  {
1173	    double advance;
1174	    if (likely (j + 1 < num_glyphs))
1175	      advance = positions[j + 1].x - positions[j].x;
1176	    else /* last glyph */
1177	      advance = run_advance - (positions[j].x - positions[0].x);
1178	    info->mask = advance * x_mult;
1179	    info->var1.i32 = x_offset;
1180	    info->var2.i32 = positions[j].y * y_mult;
1181	    info++;
1182	  }
1183	}
1184	else
1185	{
1186	  hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
1187	  for (unsigned int j = 0; j < num_glyphs; j++)
1188	  {
1189	    double advance;
1190	    if (likely (j + 1 < num_glyphs))
1191	      advance = positions[j + 1].y - positions[j].y;
1192	    else /* last glyph */
1193	      advance = run_advance - (positions[j].y - positions[0].y);
1194	    info->mask = advance * y_mult;
1195	    info->var1.i32 = positions[j].x * x_mult;
1196	    info->var2.i32 = y_offset;
1197	    info++;
1198	  }
1199	}
1200	SCRATCH_RESTORE();
1201	advances_so_far += run_advance;
1202      }
1203#undef SCRATCH_RESTORE
1204#undef SCRATCH_SAVE
1205#undef USE_PTR
1206#undef ALLOCATE_ARRAY
1207
1208      buffer->len += num_glyphs;
1209    }
1210
1211    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
1212     * or if it does, it doesn't resepct it.  So we get runs with wrong
1213     * directions.  As such, disable the assert...  It wouldn't crash, but
1214     * cursoring will be off...
1215     *
1216     * http://crbug.com/419769
1217     */
1218    if (0)
1219    {
1220      /* Make sure all runs had the expected direction. */
1221      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1222      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
1223      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
1224    }
1225
1226    buffer->clear_positions ();
1227
1228    unsigned int count = buffer->len;
1229    hb_glyph_info_t *info = buffer->info;
1230    hb_glyph_position_t *pos = buffer->pos;
1231    if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
1232      for (unsigned int i = 0; i < count; i++)
1233      {
1234	pos->x_advance = info->mask;
1235	pos->x_offset = info->var1.i32;
1236	pos->y_offset = info->var2.i32;
1237
1238	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1239
1240	info++, pos++;
1241      }
1242    else
1243      for (unsigned int i = 0; i < count; i++)
1244      {
1245	pos->y_advance = info->mask;
1246	pos->x_offset = info->var1.i32;
1247	pos->y_offset = info->var2.i32;
1248
1249	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1250
1251	info++, pos++;
1252      }
1253
1254    /* Fix up clusters so that we never return out-of-order indices;
1255     * if core text has reordered glyphs, we'll merge them to the
1256     * beginning of the reordered cluster.  CoreText is nice enough
1257     * to tell us whenever it has produced nonmonotonic results...
1258     * Note that we assume the input clusters were nonmonotonic to
1259     * begin with.
1260     *
1261     * This does *not* mean we'll form the same clusters as Uniscribe
1262     * or the native OT backend, only that the cluster indices will be
1263     * monotonic in the output buffer. */
1264    if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
1265    {
1266      hb_glyph_info_t *info = buffer->info;
1267      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
1268      {
1269	unsigned int cluster = info[count - 1].cluster;
1270	for (unsigned int i = count - 1; i > 0; i--)
1271	{
1272	  cluster = MIN (cluster, info[i - 1].cluster);
1273	  info[i - 1].cluster = cluster;
1274	}
1275      }
1276      else
1277      {
1278	unsigned int cluster = info[0].cluster;
1279	for (unsigned int i = 1; i < count; i++)
1280	{
1281	  cluster = MIN (cluster, info[i].cluster);
1282	  info[i].cluster = cluster;
1283	}
1284      }
1285    }
1286  }
1287
1288  buffer->unsafe_to_break_all ();
1289
1290#undef FAIL
1291
1292fail:
1293  if (string_ref)
1294    CFRelease (string_ref);
1295  if (line)
1296    CFRelease (line);
1297
1298  for (unsigned int i = 0; i < range_records.len; i++)
1299    if (range_records[i].font)
1300      CFRelease (range_records[i].font);
1301
1302  return ret;
1303}
1304
1305
1306/*
1307 * AAT shaper
1308 */
1309
1310HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
1311HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
1312
1313/*
1314 * shaper face data
1315 */
1316
1317struct hb_coretext_aat_shaper_face_data_t {};
1318
1319hb_coretext_aat_shaper_face_data_t *
1320_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
1321{
1322  static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
1323
1324  for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
1325  {
1326    hb_blob_t *blob = face->reference_table (tags[i]);
1327    if (hb_blob_get_length (blob))
1328    {
1329      hb_blob_destroy (blob);
1330      return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
1331    }
1332    hb_blob_destroy (blob);
1333  }
1334
1335  return nullptr;
1336}
1337
1338void
1339_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
1340{
1341}
1342
1343
1344/*
1345 * shaper font data
1346 */
1347
1348struct hb_coretext_aat_shaper_font_data_t {};
1349
1350hb_coretext_aat_shaper_font_data_t *
1351_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
1352{
1353  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
1354}
1355
1356void
1357_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
1358{
1359}
1360
1361
1362/*
1363 * shaper shape_plan data
1364 */
1365
1366struct hb_coretext_aat_shaper_shape_plan_data_t {};
1367
1368hb_coretext_aat_shaper_shape_plan_data_t *
1369_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
1370					     const hb_feature_t *user_features HB_UNUSED,
1371					     unsigned int        num_user_features HB_UNUSED,
1372					     const int          *coords HB_UNUSED,
1373					     unsigned int        num_coords HB_UNUSED)
1374{
1375  return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
1376}
1377
1378void
1379_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
1380{
1381}
1382
1383
1384/*
1385 * shaper
1386 */
1387
1388hb_bool_t
1389_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
1390			hb_font_t          *font,
1391			hb_buffer_t        *buffer,
1392			const hb_feature_t *features,
1393			unsigned int        num_features)
1394{
1395  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
1396}
1397